package com.tools.common.container;

import com.tools.common.object.C;
import com.tools.common.object.Note;
import com.tools.common.object.ObjKit;

import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * List 接口的实现类枚举
 * 用于更方便灵活地构建 List 集合
 * */
@Note("List 接口的实现类枚举，用于更方便灵活地构建 List 集合")
public enum ListEnum {

    ARRAY(ArrayList.class, "java.util.ArrayList"),

    LINKED(LinkedList.class, "java.util.LinkedList"),

    COPY_WRITE(CopyOnWriteArrayList.class, "java.util.concurrent.CopyOnWriteArrayList");

    @Note("List 集合实现类的全限定类名")
    final String implClassname;

    @Note("List 集合实现类的字节码对象")
    final Class<?> implClass;

    ListEnum(Class<?> implClass, String implClassname) {
        this.implClass = implClass;
        this.implClassname = implClassname;
    }

    public String getImplClassname() {
        return implClassname;
    }

    public Class<?> getImplClass() {
        return implClass;
    }

    @Override
    public String toString() {
        return implClassname;
    }

    /* *******************************************************************************************
     *
     *          获取枚举实例
     *
     * *******************************************************************************************
     * */


    @Note("安全地根据 implClassname 全路径获取映射的 ListEnum 实例，获取不到不会抛异常")
    public static ListEnum getEnumSafe(String implClassname) {
        if(ARRAY.implClassname.equalsIgnoreCase(implClassname)) {
            return ARRAY;
        }
        if(LINKED.implClassname.equalsIgnoreCase(implClassname)) {
            return LINKED;
        }
        if(COPY_WRITE.implClassname.equalsIgnoreCase(implClassname)) {
            return COPY_WRITE;
        }
        return null;
    }


    @Note("根据 implClassname 全路径获取映射的 ListEnum 实例，获取不到会抛异常")
    public static ListEnum getEnum(String implClassname) {
        ListEnum listEnum = getEnumSafe(implClassname);
        if(listEnum == null) throw new IllegalArgumentException("不知道【" + implClassname + "】 是什么枚举实例");
        return listEnum;
    }


    @Note("安全地根据 implClass 字节码获取映射的 ListEnum 实例，获取不到不会抛异常")
    public static ListEnum getEnumSafe(Class<?> implClass) {
        if(ARRAY.implClass.equals(implClass)) {
            return ARRAY;
        }
        if(LINKED.implClass.equals(implClass)) {
            return LINKED;
        }
        if(COPY_WRITE.implClass.equals(implClass)) {
            return COPY_WRITE;
        }
        return null;
    }

    @Note("根据 implClass 字节码实例获取映射的 ListEnum 实例，获取不到会抛异常")
    public static ListEnum getEnum(Class<?> implClass) {
        ListEnum listEnum = getEnumSafe(implClass);
        if(listEnum == null) throw new IllegalArgumentException("不知道【" + implClass + "】 是什么枚举实例");
        return listEnum;
    }

    /* *******************************************************************************************
     *
     *          直接构建 List
     *
     * *******************************************************************************************
     * */


    @Note("根据枚举值构建不同实现类实现的 List 集合")
    public <T> List<T> newList() {
        switch (this) {
            case LINKED: return new LinkedList<>();
            case COPY_WRITE: return new CopyOnWriteArrayList<>();
            default: return new ArrayList<>();
        }
    }


    @Note("根据枚举值，用不同的实现类实现 List 集合，如果是 ArrayList 则指定其初始化大小为 initSize")
    public <T>List<T> newList(int initSize) {
        initSize = Math.max(initSize, 0);
        switch (this) {
            case LINKED: return new LinkedList<>();
            case COPY_WRITE: return new CopyOnWriteArrayList<>();
            default: return new ArrayList<>(initSize);
        }
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把数组里的数据拷贝到该 List 集合里")
    @SafeVarargs
    public final <T>List<T> newList(T... elements) {
        switch (this) {
            case ARRAY: return RowKit.toArrayList(elements);
            case LINKED: return RowKit.toLinkedList(elements);
            default: return RowKit.toCopyOnWriteArrayList(elements);
        }
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把数组里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    @SafeVarargs
    public final <T>List<T> newList(Comparator<? super T> c, T... elements) {
        List<T> result = this.newList(elements);
        if(result.isEmpty()) return result;
        result.sort(c);
        return result;
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把 Collection 集合里的数据拷贝到该 List 集合里")
    public <T> List<T> newList(Collection<? extends T> elements) {
        switch (this) {
            case ARRAY: return RowKit.toArrayList(elements);
            case LINKED: return RowKit.toLinkedList(elements);
            default: return RowKit.toCopyOnWriteArrayList(elements);
        }
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把 Collection 集合里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    public <T> List<T> newList(Collection<? extends T> elements, Comparator<? super T> c) {
        List<T> result = this.newList(elements);
        if(result.isEmpty()) return result;
        result.sort(c);
        return result;
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把自定义容器集合里的数据拷贝到该 List 集合里")
    public <T> List<T> newList(OwnRows<? extends T> elements) {
        switch (this) {
            case ARRAY: return RowKit.toArrayList(elements);
            case LINKED: return RowKit.toLinkedList(elements);
            default: return RowKit.toCopyOnWriteArrayList(elements);
        }
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把自定义容器集合里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    public <T> List<T> newList(OwnRows<? extends T> elements, Comparator<? super T> c) {
        List<T> result = this.newList(elements);
        if(result.isEmpty()) return result;
        result.sort(c);
        return result;
    }


    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把可迭代容器里的数据拷贝到该 List 集合里")
    @SuppressWarnings("unchecked")
    public <T>List<T> newList(Iterable<? extends T> elements) {
        if(elements instanceof Collection) return this.newList((Collection<? extends T>) elements);
        if(elements instanceof OwnRows) return this.newList((OwnRows<? extends T>) elements);
        switch (this) {
            case ARRAY: return RowKit.toArrayList(elements);
            case LINKED: return RowKit.toLinkedList(elements);
            default: return RowKit.toCopyOnWriteArrayList(elements);
        }
    }

    @Note("根据枚举值，用不同的实现类实现 List 集合，然后把可迭代容器里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    public <T> List<T> newList(Iterable<? extends T> elements, Comparator<? super T> c) {
        List<T> result = this.newList(elements);
        if(result.isEmpty()) return result;
        result.sort(c);
        return result;
    }

    /* *******************************************************************************************
     *
     *          静态 字节码 构建
     *
     * *******************************************************************************************
     * */

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合")
    public static <T>List<T> newList(Class<?> implClass) {
        return private_getEnumIfNotExistsThrowException(implClass).newList();
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，如果实现类是 ArrayList，则指定其初始化容量")
    public static <T>List<T> newList(Class<?> implClass, int initSize) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(initSize);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把数组里的数据拷贝到该 List 集合里")
    @SafeVarargs
    public static <T>List<T> newList(Class<?> implClass, T... elements) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把数组里的数据拷贝到该 List 集合里。并对结果集进行指定规则的排序")
    @SafeVarargs
    public static <T>List<T> newList(Class<?> implClass, Comparator<? super T> c, T... elements) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(c, elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把 Collection 集合里的数据拷贝到该 List 集合里")
    public static <T>List<T> newList(Class<?> implClass, Collection<? extends T> elements) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把 Collection 集合里的数据拷贝到该 List 集合里。并对结果集进行指定规则的排序")
    public static <T>List<T> newList(Class<?> implClass, Collection<? extends T> elements, Comparator<? super T> c) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(elements, c);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把自定义容器集合里的数据拷贝到该 List 集合里")
    public static <T>List<T> newList(Class<?> implClass, OwnRows<? extends T> elements) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把自定义容器集合里的数据拷贝到该 List 集合里。并对结果集进行指定规则的排序")
    public static <T>List<T> newList(Class<?> implClass, OwnRows<? extends T> elements, Comparator<? super T> c) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(elements, c);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把可迭代容器里的数据拷贝到该 List 集合里")
    public static <T>List<T> newList(Class<?> implClass, Iterable<? extends T> iterable) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(iterable);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把可迭代容器里的数据拷贝到该 List 集合里。并对结果集进行指定规则的排序")
    public static <T>List<T> newList(Class<?> implClass, Iterable<? extends T> iterable, Comparator<? super T> c) {
        return private_getEnumIfNotExistsThrowException(implClass).newList(iterable, c);
    }

    /* *******************************************************************************************
     *
     *          静态 全路径 构建
     *
     * *******************************************************************************************
     * */

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合")
    public static <T>List<T> newList(String classname) {
        return private_getEnumIfNotExistsThrowException(classname).newList();
    }


    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，如果实现类是 ArrayList，则指定其初始化容量")
    public static <T>List<T> newList(String classname, int initSize) {
        return private_getEnumIfNotExistsThrowException(classname).newList(initSize);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把数组里的数据拷贝到该 List 集合里")
    @SafeVarargs
    public static <T>List<T> newList(String classname, T... elements) {
        return private_getEnumIfNotExistsThrowException(classname).newList(elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把数组里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    @SafeVarargs
    public static <T>List<T> newList(String classname, Comparator<? super T> c, T... elements) {
        return private_getEnumIfNotExistsThrowException(classname).newList(c, elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把 Collection 集合里的数据拷贝到该 List 集合里")
    public static <T>List<T> newList(String classname, Collection<? extends T> elements) {
        return private_getEnumIfNotExistsThrowException(classname).newList(elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把 Collection 集合里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    public static <T>List<T> newList(String classname, Collection<? extends T> elements, Comparator<? super T> c) {
        return private_getEnumIfNotExistsThrowException(classname).newList(elements, c);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把自定义容器集合里的数据拷贝到该 List 集合里")
    public static <T>List<T> newList(String classname, OwnRows<? extends T> elements) {
        return private_getEnumIfNotExistsThrowException(classname).newList(elements);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把自定义容器集合里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    public static <T>List<T> newList(String classname, OwnRows<? extends T> elements, Comparator<? super T> c) {
        return private_getEnumIfNotExistsThrowException(classname).newList(elements, c);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把可迭代容器里的数据拷贝到该 List 集合里")
    public static <T>List<T> newList(String classname, Iterable<? extends T> iterable) {
        return private_getEnumIfNotExistsThrowException(classname).newList(iterable);
    }

    @Note("使用 List 集合指定的实现类来构建出一个 List 集合，然后把可迭代容器里的数据拷贝到该 List 集合里，并依据指定的排序规则进行排序")
    public static <T>List<T> newList(String classname, Iterable<? extends T> iterable, Comparator<? super T> c) {
        return private_getEnumIfNotExistsThrowException(classname).newList(iterable, c);
    }

    /* *******************************************************************************************
     *
     *          反射构建 List 集合
     *
     * *******************************************************************************************
     * */

    @Note("根据类型包装对象构建出指定初始化容量的 List 列表")
    public static List buildList(C<?> listType, int initSize) {
        return private_buildListByC(listType, Math.max(initSize, 0));
    }


    @Note("根据类型包装对象构建出 List 列表，然后把 Collection 的数据按要求拷贝进去")
    public static List buildList(C<?> listType, Collection cs) {
        List result = private_buildListByC(listType, cs.size());
        if(result.isEmpty()) return result;
        C<?> componentType = listType.generic(0);
        if(componentType == null) {
            result.addAll(cs);
            return result;
        }
        for(Object o : cs) {
            result.add(ObjKit.toRealValue(o, componentType));
        }
        return result;
    }


    @Note("根据类型包装对象构建出 List 列表，然后把自定义集合容器的数据按要求拷贝进去")
    public static List buildList(C<?> listType, OwnRows row) {
        List result = private_buildListByC(listType, row.size());
        if(result.isEmpty()) return result;
        C<?> componentType = listType.generic(0);
        if(componentType == null) {
            for(Object o : row) {
                result.add(o);
            }
            return result;
        }
        for(Object o : row) {
            result.add(ObjKit.toRealValue(o, componentType));
        }
        return result;
    }

    @Note("根据类型包装对象构建出 List 列表，然后把可迭代容器的数据按要求拷贝进去")
    public static List buildList(C<?> listType, Iterable elements) {
        if(elements instanceof Collection) return buildList(listType, (Collection) elements);
        if(elements instanceof OwnRows) return buildList(listType, (OwnRows) elements);
        int size = RowKit.getIterableSize(elements);
        List result = private_buildListByC(listType, size);
        if(size == 0) return result;
        C<?> componentType = listType.generic(0);
        if(componentType != null) {
            for(Object o : elements) {
                Object value = ObjKit.toRealValue(o, componentType);
                result.add(value);
            }
            return result;
        }
        for (Object o : elements) {
            result.add(o);
        }
        return result;
    }


    @Note("根据类型包装对象构建出 List 列表，然后把数组内的数据按要求拷贝进去")
    public static List buildList(C<?> listType, Object array) {
        if(array == null || !array.getClass().isArray()) {
            return private_buildListByC(listType, 0);
        }
        int length = Array.getLength(array);
        List result = private_buildListByC(listType, length);
        if(length == 0) return result;
        C<?> componentType = listType.generic(0);
        if(componentType == null) {
            for (int i = 0; i < length; i++) {
                result.add(Array.get(array, i));
            }
            return result;
        }
        for (int i = 0; i < length; i++) {
            Object o = Array.get(array, i);
            result.add(ObjKit.toRealValue(o, componentType));
        }
        return result;
    }


    /* *******************************************************************************************
     *
     *          私有逻辑
     *
     * *******************************************************************************************
     * */

    @Note("根据 List 集合实现类的字节码获取枚举映射的实例，如果获取不到则抛出异常")
    private static ListEnum private_getEnumIfNotExistsThrowException(Class<?> implClass) {
        if(Collection.class.equals(implClass) || List.class.equals(implClass)) {
            return ARRAY;
        }
        return getEnum(implClass);
    }

    @Note("根据 List 集合实现类的全路径获取枚举映射的实例，如果获取不到则抛出异常")
    private static ListEnum private_getEnumIfNotExistsThrowException(String classname) {
        if("java.util.Collection".equals(classname) || "java.util.List".equals(classname)) {
            return ARRAY;
        }
        return getEnum(classname);
    }


    @Note("通过类型包装对象构建一个 java.util.List 列表对象")
    private static List private_buildListByC(C<?> c, int listSize) {
        Class<?> mainType = c.getMainType();
        if(Collection.class.equals(mainType) || List.class.equals(mainType) || ArrayList.class.equals(mainType)) {
            if(c.argCount() == 0) {
                return (listSize < 1) ? new ArrayList<>(): new ArrayList<>(listSize);
            }
            Object first = c.getArgValue(0);
            if(first instanceof Collection) {
                return new ArrayList<>((Collection<?>) first);
            }
            return (listSize < 1) ? new ArrayList<>(): new ArrayList<>(listSize);
        }
        if(LinkedList.class.equals(mainType)) {
            if(c.argCount() == 0) {
                return new LinkedList<>();
            }
            Object first = c.getArgValue(0);
            if(first instanceof Collection) {
                return new LinkedList<>((Collection<?>) first);
            }
            return new LinkedList<>();
        }
        if(CopyOnWriteArrayList.class.equals(mainType)) {
            if(c.argCount() == 0) {
                return new CopyOnWriteArrayList<>();
            }
            Object first = c.getArgValue(0);
            if(first instanceof Collection) {
                return new CopyOnWriteArrayList<>((Collection<?>) first);
            }
            if(first.getClass().isArray()) {
                return RowKit.toCopyOnWriteArrayList(first, c);
            }
            return new CopyOnWriteArrayList<>();
        }
        return (List) ObjKit.buildObject(c);
    }

}
